package org.fuys.coder.infrastructure.repository;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.fuys.coder.common.constants.RedisConstants;
import org.fuys.coder.common.constants.ResultMessageConstants;
import org.fuys.coder.common.entity.Pair;
import org.fuys.coder.common.exception.BusinessException;
import org.fuys.coder.domain.auth.model.vo.UserVo;
import org.fuys.coder.common.entity.PageDTO;
import org.fuys.coder.domain.user.model.req.repo.UserInfoSelectReq;
import org.fuys.coder.domain.user.model.req.repo.UserInfoUpdateReq;
import org.fuys.coder.domain.user.model.vo.operation.UserStopVO;
import org.fuys.coder.domain.user.model.vo.repo.AuthorVO;
import org.fuys.coder.domain.user.model.vo.repo.UserStatusTypeVO;
import org.fuys.coder.domain.user.repository.IUserRepository;
import org.fuys.coder.infrastructure.dao.UserFollowerMapper;
import org.fuys.coder.infrastructure.dao.UserMapper;
import org.fuys.coder.infrastructure.dao.UserStopMapper;
import org.fuys.coder.infrastructure.model.po.User;
import org.fuys.coder.infrastructure.model.po.UserFollower;
import org.fuys.coder.infrastructure.model.po.UserStop;
import org.fuys.coder.infrastructure.util.RedisUtil;
import org.springframework.stereotype.Service;
import org.springframework.util.ObjectUtils;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @projectName: fuys-low-coder
 * @package: org.fuys.coder.infrastructure.repository
 * @className: UserRepositoryImpl
 * @author: WangJing
 * @description: 用户仓储实现类
 * @date: 2024/6/30 16:33
 * @version: 1.0
 */
@Service
public class UserRepositoryImpl extends ServiceImpl<UserMapper, User> implements IUserRepository {

    @Resource
    private UserMapper userMapper;

    @Resource
    private UserFollowerMapper userFollowerMapper;

    //todo 违背了DDD原则 之后会更改
    @Resource
    private UserFollowerServiceImpl userFollowerServiceImpl;

    @Resource
    private UserStopMapper userStopMapper;

    @Resource
    private RedisUtil redisUtil;

    @Override
    public void updateUserPoint(Integer userId, Integer value) {
        final User user = userMapper.selectOne(new LambdaQueryWrapper<User>().select(User::getPoints).eq(User::getId, userId));
        user.setPoints(user.getPoints()+value);
        user.setId(userId);
        userMapper.updateById(user);
    }

    @Override
    public int getUserPoint(Integer userId) {
        return userMapper.selectOne(new LambdaQueryWrapper<User>().select(User::getPoints).eq(User::getId, userId))
                .getPoints();
    }

    @Override
    public boolean updateUserInfo(UserInfoUpdateReq req, Integer userId) {
        final User user = userMapper.selectOne(new LambdaQueryWrapper<User>().select(User::getId).eq(User::getId, userId));
        if(ObjectUtils.isEmpty(user)){
            return false;
        }
        user.setIntroduce(req.getIntroduce());
        user.setNickName(req.getUsername());
        user.setAvatar(req.getFileId().toString());
        userMapper.updateById(user);
        return true;
    }

    @Override
    public UserVo getUserInfo(Integer userId) {
        final User user = userMapper.selectOne(new LambdaQueryWrapper<User>().select(User::getNickName, User::getAvatar, User::getIntroduce
                        , User::getFollowerCount, User::getLikeCount, User::getFavCount, User::getPoints, User::getSubstanceCount, User::getStatus
                ,User::getEmail)
                .eq(User::getId, userId));
        UserVo userVo=new UserVo();
        userVo.setPoint(user.getPoints());
        userVo.setUsername(user.getNickName());
        userVo.setIntroduce(user.getIntroduce());
        userVo.setAvatar(user.getAvatar());
        userVo.setFollowerCount(user.getFollowerCount());
        userVo.setFavCount(user.getFavCount());
        userVo.setLikeCount(user.getLikeCount());
        userVo.setSubstanceCount(user.getSubstanceCount());
        userVo.setStatus(user.getStatus());
        userVo.setEmail(user.getEmail());
        return userVo;
    }

    @Override
    public Integer getUserStatus(Integer userId) {
        final User user = userMapper.selectOne(new LambdaQueryWrapper<User>().select(User::getStatus)
                .eq(User::getId, userId));
        if(ObjectUtils.isEmpty(user)){
            return UserStatusTypeVO.USER_STATUS_DELETE;
        }
        return user.getStatus();
    }

    @Override
    public List<Integer> getUserFollowers(Integer userId,Integer type) {
        final List<UserFollower> userFollowers = userFollowerMapper.selectList(new LambdaQueryWrapper<UserFollower>()
                .select(UserFollower::getUserId).eq(UserFollower::getAuthorId, userId).eq(UserFollower::getType,type));
        if(ObjectUtils.isEmpty(userFollowers)) {
            return null;
        }
        return userFollowers.stream().map(UserFollower::getUserId).collect(Collectors.toList());
    }

    @Override
    public List<Pair<Integer,Integer>> getUserNoticed(Integer userId){
        final List<UserFollower> userFollowers = userFollowerMapper.selectList(new LambdaQueryWrapper<UserFollower>()
                .select(UserFollower::getAuthorId, UserFollower::getType).eq(UserFollower::getUserId, userId));
        if(ObjectUtils.isEmpty(userFollowers)){
            return null;
        }
        return userFollowers.stream().map(item -> {
            final Pair<Integer, Integer> pair = new Pair<>();
            pair.setLeft(item.getAuthorId());
            pair.setRight(item.getType());
            return pair;
        }).collect(Collectors.toList());
    }

    @Override
    public void updateUserNoticedAuthor(List<Pair<Integer, Integer>> collect, Integer userId) {
        //todo 是否有更简单的方式 可以不用全部更新？而是排除数据库中已经存在的？
        List<UserFollower> list=new ArrayList<>();
        collect.forEach(item->{
            UserFollower userFollower=new UserFollower();
            userFollower.setUserId(userId);
            userFollower.setAuthorId(item.getLeft());
            userFollower.setType(item.getRight());
            list.add(userFollower);
        });
        userFollowerServiceImpl.saveOrUpdateBatch(list);
    }

    @Override
    public List<AuthorVO> getUserNoticedVos(Integer userId, PageDTO pageDTO) {
        final List<User> users = userFollowerMapper.selectUserNoticedVos(userId,
                (pageDTO.getCurPage()-1)* pageDTO.getPageNum(), pageDTO.getPageNum());
        if(ObjectUtils.isEmpty(users)){
            return null;
        }
        return users.stream().map(item->{
            AuthorVO authorVO=new AuthorVO();
            authorVO.setAvatar(Long.valueOf(item.getAvatar()));
            authorVO.setUserId(item.getId());
            authorVO.setUserName(item.getNickName());
            authorVO.setIntroduce(item.getIntroduce());
            authorVO.setFollowCount(item.getFollowerCount());
            return authorVO;
        }).collect(Collectors.toList());
    }

    @Override
    public List<AuthorVO> getUserFollowerVos(Integer userId,Integer type,PageDTO pageDTO) {
        List<User> users = userFollowerMapper.selectUserFollowerVos(userId,type,(pageDTO.getCurPage()-1)* pageDTO.getPageNum(),
                pageDTO.getPageNum());
        if(ObjectUtils.isEmpty(users)){
            return null;
        }
        return users.stream().map(item->{
            AuthorVO authorVO=new AuthorVO();
            authorVO.setUserId(item.getId());
            authorVO.setUserName(item.getNickName());
            authorVO.setAvatar(Long.valueOf(item.getAvatar()));
            return authorVO;
        }).collect(Collectors.toList());
    }

    @Override
    public List<UserVo> getUserInfoByCondition(UserInfoSelectReq selectReq) {
        final Integer userId = selectReq.getUserId();
        final String email = selectReq.getEmail();
        final String nickName = selectReq.getNickName();
        final List<User> users = userMapper.selectList(new LambdaQueryWrapper<User>()
                .eq(!ObjectUtils.isEmpty(userId), User::getId, userId)
                .eq(!ObjectUtils.isEmpty(email), User::getEmail, email)
                .like(!ObjectUtils.isEmpty(nickName), User::getNickName, nickName));
        if(ObjectUtils.isEmpty(users)){
            return null;
        }
        return users.stream().map(item->{
            UserVo userVo=new UserVo();
            userVo.setId(item.getId());
            userVo.setAvatar(item.getAvatar());
            userVo.setUsername(item.getNickName());
            userVo.setIntroduce(item.getIntroduce());
            userVo.setFavCount(item.getFavCount());
            userVo.setPoint(item.getPoints());
            userVo.setLikeCount(item.getLikeCount());
            userVo.setEmail(item.getEmail());
            userVo.setPassword(item.getPassword());
            userVo.setSubstanceCount(item.getSubstanceCount());
            userVo.setStatus(item.getStatus());
            return userVo;
        }).collect(Collectors.toList());
    }

    @Override
    public boolean freezeUser(Integer userId,Date date,String email) {
        try {
            final String redisKey = RedisConstants.REDIS_FIELD_USER + RedisConstants.REDIS_USE_STOP + RedisConstants.REDIS_SPLIT
                    + email;
            UserStopVO userStopVO=new UserStopVO();
            userStopVO.setUserId(userId);
            userStopVO.setOpen(date);
            redisUtil.commonSet(redisKey,userStopVO);
            UserStop stopRecord = userStopMapper.selectOne(new LambdaQueryWrapper<UserStop>()
                    .select(UserStop::getId).eq(UserStop::getUserId, userId));
            if(ObjectUtils.isEmpty(stopRecord)) {
                stopRecord=new UserStop();
                stopRecord.setOpenTime(date);
                stopRecord.setUserId(userId);
                userStopMapper.insert(stopRecord);
            }else{
                stopRecord.setUserId(userId);
                stopRecord.setOpenTime(date);
                userStopMapper.updateById(stopRecord);
            }
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }

    @Override
    public boolean updateUserStatus(Integer userId,Integer status) {
        try {
            User user=new User();
            user.setId(userId);
            user.setStatus(status);
            userMapper.updateById(user);
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }

    @Override
    public void unFreezeUser(Integer userId,String email) {
        final String redisKey = RedisConstants.REDIS_FIELD_USER + RedisConstants.REDIS_USE_STOP + RedisConstants.REDIS_SPLIT
                + email;
        redisUtil.deleteKey(redisKey);
        userStopMapper.delete(new LambdaQueryWrapper<UserStop>()
                .eq(UserStop::getUserId,userId));
        User user=new User();
        user.setId(userId);
        user.setStatus(UserStatusTypeVO.USER_STATUS_NORMAL);
        userMapper.updateById(user);
    }

    @Override
    public Pair<List<AuthorVO>,Long> getAuthorVOByName(Integer pageNum, Integer curPage, String keywords) {
        Page<User> page=new Page<>(curPage,pageNum);
        final Page<User> userPage = userMapper.selectPage(page, new LambdaQueryWrapper<User>()
                .select(User::getNickName,User::getId,User::getFollowerCount,User::getIntroduce,User::getAvatar)
                .like(User::getNickName, keywords));
        if(ObjectUtils.isEmpty(userPage)){
            return null;
        }
        if(ObjectUtils.isEmpty(userPage.getRecords())){
            return null;
        }
        final List<AuthorVO> collect = userPage.getRecords().stream().map(item -> {
            AuthorVO authorVO = new AuthorVO();
            authorVO.setUserId(item.getId());
            authorVO.setUserName(item.getNickName());
            authorVO.setIntroduce(item.getIntroduce());
            authorVO.setFollowCount(item.getFollowerCount());
            authorVO.setAvatar(Long.valueOf(item.getAvatar()));
            return authorVO;
        }).collect(Collectors.toList());
        return new Pair<List<AuthorVO>, Long>(collect,userPage.getTotal());
    }

    @Override
    public String getUserNameById(Integer fromId) {
        final User user = userMapper.selectOne(new LambdaQueryWrapper<User>()
                .select(User::getNickName).eq(User::getId, fromId)
        );
        if(ObjectUtils.isEmpty(user)){
            return null;
        }
        return user.getNickName();
    }

    @Override
    public void updateUserFollower(Integer authorId, int num) {
        User user=new User();
        user.setId(authorId);
        user.setFollowerCount(user.getFollowerCount()+num);
        userMapper.updateById(user);
    }

    @Override
    public UserStopVO getFreezeUser(String email) {
        String redisKey= RedisConstants.REDIS_FIELD_USER+RedisConstants.REDIS_USE_STOP
                + RedisConstants.REDIS_SPLIT + email;
        final Object o = redisUtil.commonGet(redisKey);
        if(o!=null){
            return (UserStopVO) o;
        }
        return null;
    }
}
